package com.mate.cloud.redisson.service;

import com.google.common.collect.Lists;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


/**
 * 标签自动补全（使用 Sorted Set）
 * @author:         MI
 * @email:          448341911@qq.com
 * @createTime:     2025/8/19 10:23
 * @updateUser:     MI
 * @updateTime:     2025/8/19 10:23
 * @updateRemark:   修改内容
 * @version:        1.0
 */
@Slf4j
@Service
public class TagAutoCompleteService {

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    private static final String AUTOCOMPLETE_KEY = "tag:autocomplete";

    /**
     * 添加标签到自动补全索引
     */
    public void addTagToAutocomplete(String tagName) {
        // 为标签的每个前缀创建索引
        for (int i = 1; i <= tagName.length(); i++) {
            String prefix = tagName.substring(0, i);
            redisTemplate.opsForZSet().add(
                    AUTOCOMPLETE_KEY + ":" + prefix,
                    tagName,
                    0
            );
        }
        // 添加完整标签
        redisTemplate.opsForZSet().add(
                AUTOCOMPLETE_KEY + ":" + tagName,
                tagName,
                0
        );
    }

    /**
     * 获取标签自动补全建议
     */
    public Set<String> getSuggestions(String prefix) {
        String key = AUTOCOMPLETE_KEY + ":" + prefix.toLowerCase();
        return redisTemplate.opsForZSet().range(key, 0, 10);
    }

    public Set<String> getItemsByAnyTags(Set<String> tags, int limit,int page) {
        // 1. 创建临时键
        String tempKey = "temp:union:" + UUID.randomUUID();

        // 2. 生成标签键列表
        List<String> tagKeys = tags.stream()
                .map(tag -> "tag:" + tag)
                .collect(Collectors.toList());

        // 3. 创建并集（使用管道优化性能）
        redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
            connection.sUnionStore(tempKey.getBytes(),
                    tagKeys.stream().map(String::getBytes).toArray(byte[][]::new));
            connection.expire(tempKey.getBytes(), 300); // 5分钟过期
            return null;
        });

        // 4. 创建分页的 ZSet
        String zsetKey = "temp:zset:" + UUID.randomUUID();
        long total = redisTemplate.opsForSet().size(tempKey);

        // 5. 分批处理大集合
        int batchSize = 1000;
        long cursor = 0;
        do {
            ScanOptions options = ScanOptions.scanOptions().count(batchSize).build();
            Cursor<String> scanCursor = redisTemplate.opsForSet().scan(tempKey, options);

            List<DefaultTypedTuple<String>> tuples = Lists.newArrayList();
            while (scanCursor.hasNext()) {
                String member = scanCursor.next();
                tuples.add(new DefaultTypedTuple<>(member, 0.0));
            }

            if (!tuples.isEmpty()) {
                // 关键修正：将 List 转换为 Set
                redisTemplate.opsForZSet().add(zsetKey, new HashSet<>(tuples));
            }

            cursor = scanCursor.getCursorId();
            scanCursor.close();
        } while (cursor != 0);

        // 6. 设置 ZSet 过期时间
        redisTemplate.expire(zsetKey, 5, TimeUnit.MINUTES);

        // 7. 获取分页结果
        long start = (long) (page - 1) * limit;
        long end = start + limit - 1;
        Set<String> result = redisTemplate.opsForZSet().range(zsetKey, start, end);

        return result != null ? result : Collections.emptySet();
    }

    // 批量添加标签
    public void addTagsToItem(String itemId, Set<String> tags) {
        String itemTagsKey = "item:" + itemId + ":tags";

        // 使用pipeline批量操作
        redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
            for (String tag : tags) {
                String tagKey = "tag:" + tag;
                connection.sAdd(tagKey.getBytes(), itemId.getBytes());
                connection.sAdd(itemTagsKey.getBytes(), tag.getBytes());
                connection.zIncrBy("tag:hot".getBytes(), 1, tag.getBytes());
            }
            return null;
        });
    }

    // 基于标签名称的分片
    private String getShardedTagKey(String tagName) {
        int shard = Math.abs(tagName.hashCode()) % 16;
        return "tag:" + tagName + ":" + shard;
    }

    /**
     * 缓存穿透防护
     * @author      MI
     * @param
     * @return
     * @throws
     * @date        2025/8/19 10:33
     */
//    public Set<String> getItemsByTagSafe(String tagName) {
//        String tagKey = "tag:" + tagName;
//
//        // 使用布隆过滤器检查标签是否存在
//        if (!bloomFilter.mightContain(tagName)) {
//            return Collections.emptySet();
//        }
//
//        return redisTemplate.opsForSet().members(tagKey);
//    }
}
